package com.gitee.cui.concurrency.concurrent;

import com.gitee.cui.util.Print;
import com.gitee.cui.util.ThreadUtil;
import org.junit.Test;

import java.util.concurrent.*;

/**
 * 使用Java8提供的CompletableFuture异步处理类实现异步功能
 *
 * @author cuiqingqiang
 * @version 1.0
 * @date 2021/12/10 13:39
 **/
public class CompletableFutureDemo {

    /**
     * 测试一个无输入参数、无返回值的异步任务
     */
    @Test
    public void runAsyncTest() throws ExecutionException, InterruptedException, TimeoutException {
        CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
            ThreadUtil.sleepSeconds(1);
            Print.tcfo("run end ......");
        });
        future.get(2, TimeUnit.SECONDS);
    }

    /**
     * 测试一个无输入参数，有返回值的异步任务
     */
    @Test
    public void supplyAsyncTest() throws ExecutionException, InterruptedException, TimeoutException {
        CompletableFuture<Long> future = CompletableFuture.supplyAsync(() -> {
            long start = System.currentTimeMillis();
            ThreadUtil.sleepSeconds(1);
            Print.tcfo("run end ......");
            return System.currentTimeMillis() - start;
        });
        Long time = future.get(2, TimeUnit.SECONDS);
        Print.tcfo("异步执行耗时（秒） = " + time / 1000);
    }

    /**
     * 为子任务设置完成钩子和异常钩子测试程序
     */
    @Test
    public void whenCompleteTest() throws ExecutionException, InterruptedException {
        CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
            ThreadUtil.sleepSeconds(1);
            Print.tcfo("抛出异常！");
            throw new RuntimeException("发生异常");
        });

        future.whenComplete((unused, throwable) -> Print.tcfo("执行完成"));

        future.exceptionally(throwable -> {
            Print.tcfo("执行失败：" + throwable.getMessage());
            return null;
        });
        future.get();
    }

    /**
     * 测试handle处理子任务
     */
    @Test
    public void handleTest() throws ExecutionException, InterruptedException {
        CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
            // 模拟异步任务执行
            ThreadUtil.sleepSeconds(1);
            Print.tcfo("抛出异常");
            throw new RuntimeException("发生异常");
        });

        future.handle((unused, throwable) -> {
            if (throwable == null) {
                Print.tcfo("没有发生异常");
            } else {
                Print.tcfo("sorry, 发生了异常");
            }
            return null;
        });

        future.get();
    }

    /**
     * 测试采用自己提供的线程池运行子任务
     */
    @Test
    public void threadPoolTest() throws ExecutionException, InterruptedException, TimeoutException {
        ThreadPoolExecutor pool = ThreadUtil.getMixedTargetThreadPool();
        CompletableFuture<Long> future = CompletableFuture.supplyAsync(() -> {
            Print.tcfo("run begin ......");
            long startTime = System.currentTimeMillis();
            ThreadUtil.sleepSeconds(1);
            Print.tcfo("run end ......");
            return System.currentTimeMillis() - startTime;
        }, pool);

        Long time = future.get(2, TimeUnit.SECONDS);
        Print.tcfo("异步执行耗时：" + time / 1000);
    }

    /**
     * 串行执行异步任务的方式
     */
    @Test
    public void thenApplyTest() throws ExecutionException, InterruptedException {
        CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
            int firstStep = 10 + 10;
            Print.tcfo("firstStep outcome is " + firstStep);
            return firstStep;
        }).thenApply((firstStepOutCome) -> {
            int secondStep = firstStepOutCome * 2;
            Print.tcfo("secondStep outcome is " + secondStep);
            return secondStep;
        });

        Integer result = future.get();
        Print.tcfo("outcome is " + result);
    }
}
